/* The MIT License (MIT)

	Copyright (c) 2013 Schpitt <schpitt@gmail.com>
	https://code.google.com/p/updator/

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE. */

#ifndef _UPDATOR_H_
#define _UPDATOR_H_

#include <string>
#include <vector>

namespace sf {
	class Thread;
};

namespace Updator 
{
	class IUpdateListener;
	class Downloader;
	class TaskQueue;

	class Updator
	{

		std::string      hash_filename;
		bool             stopped;
		IUpdateListener* listener;
		Downloader*      downloader;
		
		TaskQueue* tasks_to_check;
		TaskQueue* tasks_to_execute; // download or delete
		TaskQueue* tasks_to_postexecute;

		volatile unsigned char check_thread_running;
		volatile bool execute_thread_running;
							
		const unsigned char check_thread_number;
		const unsigned int  check_buffer_size;
		const unsigned char postexecute_thread_number;
		const unsigned int  postexecute_buffer_size;

	public:

		Updator( const std::string& p_host, 
				 const std::string& p_folder, 
				 const std::string& p_hash_filename, 
				 unsigned char p_check_thread_number = 2,       // thread to compute hash (0 : on main thread)
				 unsigned int  p_check_buffer_size = 500000,    // heap memory to compute hash
				 unsigned char p_postexecute_thread_number = 2, // thread to decompress file (0 : on main thread)
				 unsigned int  p_postexecute_buffer_size = 100000 ); // heap memory to decompress file
		~Updator();

		void setListener(IUpdateListener* p_listener);
	
		void startUpdate();
		void stopUpdate();

		// internal methods
		void checkTasks();
		void executeTasks();
		void postExecuteTasks();
		void downloadProgress( int p_size );

	private:
		void startCheckers(std::vector<sf::Thread*>& p_threads);
		void startExecuters(sf::Thread* p_thread);
		void startPostExecuters(std::vector<sf::Thread*>& p_threads);
		void waitForAll(std::vector<sf::Thread*>& p_checkers, sf::Thread* p_thread, std::vector<sf::Thread*>& p_post_executor);

		bool getFileInfo( std::string& p_fileinfo );
		bool prehandleFileInfo( std::string& p_fileinfo );
	};
}

#endif
